package gupao.concurrency.simpleweb;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class MockClient {

    final static String url = "http://localhost:8080/calc";
    final static HttpEntity<String> entity = new HttpEntity<>(new HttpHeaders());

    final static RestTemplate restTemplate = new RestTemplate();
    final static AtomicBoolean stop = new AtomicBoolean(false);

    public static void main(String[] args) throws Exception {
        test(10,60);
    }

    static void test(int concurrency, long runTimeInSecond) throws InterruptedException {
        int poolSize = Math.min(100, concurrency);
        ExecutorService executor = new ThreadPoolExecutor(concurrency, concurrency,
                0L,TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(1000),
                new SimpleThreadFactory("client-thread-"));

        List<Task> tasks = generateTask(concurrency);
        tasks.forEach(t -> executor.submit(t));

        System.out.println("wait...");
        TimeUnit.SECONDS.sleep(runTimeInSecond);
        System.out.println("completed.");
        executor.shutdownNow();
    }

    static List<Task> generateTask(int taskNum){
        List<Task> list = new ArrayList<>();
        for(int i = 0; i < taskNum; i++){
            list.add(new Task("task-" + i));
        }
        return list;
    }

    static class SimpleThreadFactory implements ThreadFactory {
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String prefix;

        public SimpleThreadFactory(String prefix) {
            this.prefix = prefix;
        }

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread( r,
                    prefix + threadNumber.getAndIncrement());
            t.setDaemon(true);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);

            log.info("{} create sub thread {}", Thread.currentThread().getName(), t.getName());

            return t;
        }
    }

    @RequiredArgsConstructor
    static class Task implements Callable<String>{
        final String name;
        int count = 0;
        @Override
        public String call() throws Exception {
            while(!stop.get()){
                ResponseEntity<String> rsp = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
                if(count++ % 10 == 0){
                    System.out.println(MessageFormat.format("{0} run {1} times, get body: {2}", name, count, rsp.getBody()));
                }
            }
            return name + " finished.";
        };
    }

}
